package com.zrwl.poscloud.xo.utils;

import com.alibaba.fastjson.JSONObject;
import com.zrwl.poscloud.base.constants.Constants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Component
public class RestTemplateUtil {

    private static final Pattern QUERY_PARAM_PATTREN = Pattern.compile("([^&=]+)(=?)([^&]+)?");

    public static final String GET = "GET";
    public static final String POST = "POST";
    public static final String PUT = "PUT";
    public static final String DELETE = "DELETE";

    @Resource
    private RestTemplate restTemplate;

    public ResponseEntity<String> post(String url, Map<String, Object> params) {
        ResponseEntity<String> entity = restTemplate.postForEntity(url, params, String.class);
        return entity;
    }

    public <T> T get(String url, Map<String, Object> params, Class<T> responseType) {
        return restTemplate.getForEntity(expandURL(url, params.keySet()), responseType, params).getBody();
    }

    public <T> ResponseEntity<T> doRequest(String reqType, String url, String contentType, Map<String, String> headerMap, String argType, Map<String, Object> params, Class<T> responseType) {
        log.info("doRequest reqType:"+reqType+" params:"+params+" argType:"+ argType);
        HttpHeaders hders = new HttpHeaders();

        if(StringUtils.isNotEmpty(contentType)) {
            if(contentType.contains("application/json")) {
                hders.setContentType(MediaType.APPLICATION_JSON);
            } else if(contentType.contains("application/x-www-form-urlencoded")) {
                hders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            }
            headerMap.remove("Content-Type");
        }

        for(Map.Entry<String,String> entry : headerMap.entrySet()) {
            hders.add(entry.getKey(), entry.getValue());
        }

        //有些post的form请求，在URI和BODY中同时有参数
        Map<String,Object> uriValueMap = null;
        if(params != null && params.containsKey(Constants.ArgKey_URIParamMap)){
            uriValueMap = (Map<String, Object>) params.get(Constants.ArgKey_URIParamMap);
            params.remove(Constants.ArgKey_URIParamMap);
        }

        HttpEntity<?> requestEntity = (contentType != null && contentType.contains(MediaType.APPLICATION_JSON_VALUE))?
                new HttpEntity<Map>(params, hders) : (MediaType.APPLICATION_FORM_URLENCODED_VALUE.equalsIgnoreCase(contentType) ?
                new HttpEntity<MultiValueMap>(createMultiValueMap(params), hders) : new HttpEntity<>(null, hders));
        Map<String, Object> uriVariables = new HashMap<>();
        if(uriValueMap != null){
            url = expandURL(url, uriValueMap.keySet());
            uriVariables = uriValueMap;
        } else if(Constants.ArgType_URL.equals(argType)) {//参数在url的?后
            url = expandURL(url, params.keySet());
            uriVariables = params;
        }
        log.info("doRequest url: "+url+" uriValueMap:"+uriValueMap+" uriVariables:"+uriVariables+" params:"+params+" headermap:"+ hders);
        ResponseEntity<T> responseEntity = null;
        if(reqType.equals(GET)) {
            if(url.contains(".do")) { //京源系统有response body为chunk的情况，resttemplate会报异常
                log.info(".do url:"+url+" uriVariables:"+uriVariables);
                String getBody = HttpUtil.get(url, headerMap, uriVariables);
                if(getBody != null) {
                    return new ResponseEntity<T>((T) getBody.getBytes(), null, HttpStatus.OK);
                } else {
                    return new ResponseEntity<T>(null, null, HttpStatus.INTERNAL_SERVER_ERROR);
                }
            } else {
                responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, responseType, uriVariables);
            }
        }
        if(reqType.equals(POST)) {
            responseEntity = restTemplate.postForEntity(url, requestEntity, responseType, uriVariables);
        }

        return responseEntity;
    }

    public static MultiValueMap<String, String> createMultiValueMap(JSONObject params) {
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        if(params != null) {
            for(String key : params.keySet()) {
                if(params.get(key) instanceof List) {
                    for(Iterator<String> it = ((List<String>) params.get(key)).iterator(); it.hasNext(); ) {
                        String value = it.next();
                        map.add(key, value);
                    }
                } else {
                    map.add(key, params.getString(key));
                }
            }

        }
        return map;
    }

    public static MultiValueMap<String, String> createMultiValueMap(Map<String, Object> params) {
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        if(params != null) {
            for (Map.Entry entry: params.entrySet()) {
                map.add(entry.getKey().toString(), entry.getValue().toString());
            }
        }
        return map;
    }

    public static String expandURL(String url, Set<?> keys) {
        Matcher mc = RestTemplateUtil.QUERY_PARAM_PATTREN.matcher(url);
        StringBuilder sb = new StringBuilder(url);
        if (!mc.find()) {
            sb.append("&");
        } else {
            sb.append("?");
        }

        for (Object key : keys) {
            sb.append(key).append("=").append("{").append(key).append("}").append("&");
        }
        return sb.deleteCharAt(sb.length() - 1).toString();
    }
}
